<?php

namespace app\base\command;


use app\base\model\RedianData;
use app\base\model\RedianTask;
use app\base\service\MemberService;
use app\base\service\TaskService;
use think\admin\Command;
use think\console\Input;
use think\console\Output;
/**
 * 采集任务运行v1版
 *
 * 分时段运行任务 采集数量根据产出数量计算
 * Class SmsNum
 * @package app\common\command
 */
class TaskRunV1 extends Command
{
    /**
     * 配置指令
     */
    protected function configure()
    {
        $this->setName('xbase:TaskRunV1');
        $this->setDescription('TaskRunV1');
    }

    protected function execute(Input $input, Output $output)
    {
        $queue_data = $this->queue->data;
        $task_id = $queue_data['task_id'];
        $task_run_log_id = 0;
        if(isset($queue_data['task_run_log_id'])){
            $task_run_log_id = $queue_data['task_run_log_id'];
        }
        $this->setQueueProgress("开始执行任务", 0);
        $task = RedianTask::mQuery()->where([ "id"=>$task_id])->find();
        if(empty($task)){
           // $this->error('任务不存在');
            $this->setQueueError("任务不存在");
        }
        $progress = $task['progress'];
        if($progress==0 || $progress==1 || $progress==2){

            $this->checkBeans($task,2,$task_run_log_id);

            //开始采集任务
            $r = $this->dataMatch($task,$task_run_log_id);
            if($r){
                $progress=3;
            }else{
                RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"采集失败:无匹配采集结果",'error_status'=>1,'status'=>1]);
                if($task_run_log_id){
                    $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"采集失败:无匹配采集结果",'error_status'=>1]);
                }
                $this->setQueueError("任务执行失败:无匹配采集结果");
            }

        }




        if( $progress==3){
            $this->checkBeans($task,3,$task_run_log_id);
            //口播文本生成
            $this->setQueueProgress("开始口播文本生成,请稍等...", 40);
            RedianTask::mQuery()->where([ "id"=>$task_id])->update(['progress'=>3]);
            if($task_run_log_id){
                $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['progress'=>3]);
            }
            $f = true;
            $f_num = 0;
            while ($f){
                $f = $this->textGenerate($task,$task_run_log_id);
                $f_num++;
                if($f_num>5){
                    $f = false;

                }

            }
            $c = RedianData::mQuery()->where(['task_id'=>$task['id'],'gaixie_status'=>2,'task_run_log_id'=>$task_run_log_id])->count();
            if($c==0){
                RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"AI改写失败",'error_status'=>3,'status'=>1]);
                if($task_run_log_id){
                    $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"AI改写失败",'error_status'=>3]);
                }
                $this->setQueueError("任务执行失败:AI改写失败");
            }



            $progress=4;
        }


        if($progress==4){
            $this->checkBeans($task,4,$task_run_log_id);
            //音频生成
            $this->setQueueProgress("开始音频生成,请稍等...", 60);
            RedianTask::mQuery()->where([ "id"=>$task_id])->update(['progress'=>4]);
            if($task_run_log_id){
                $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['progress'=>4]);
            }
            $redian_data = TaskService::instance()->audioGenerate($task,$task_run_log_id);
            if(empty($redian_data)){
                RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"音频生成失败",'error_status'=>4,'status'=>1]);
                if($task_run_log_id){
                    $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"音频生成失败",'error_status'=>4]);
                }
                $this->setQueueError("任务执行失败:音频生成失败111");

            }
            //使用蝉镜生成音频,需等待蝉镜音频生成完成
            if($task['audio_platform']=="蝉镜"){
                $audio_result = false;
                while (!$audio_result){
                    $this->setQueueProgress("等待音频生成结果{$audio_result}");
                    sleep(60);
                    //还有正在生成中的音频生成任务继续等待
                    $mun = RedianData::mQuery()->where(["task_id"=>$task_id,"task_run_log_id"=>$task_run_log_id])->where(['audio_status'=>2])->count();
                    if($mun>0){
                        $this->setQueueProgress("有音频生成任务正在处理中...{$mun}");
                    }else{
                        $audio_result = true;
                        $this->setQueueProgress("音频生成完成");
                    }
                }
                sleep(30);
                $r = RedianData::mQuery()->where(["task_id"=>$task_id,"task_run_log_id"=>$task_run_log_id])->where(['audio_status'=>3])->count();
                $this->setQueueProgress("音频生成结果{$r}");
                if($r==0){
                    RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"音频生成失败",'error_status'=>4,'status'=>1]);
                    if($task_run_log_id){
                        $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"音频生成失败",'error_status'=>4]);
                    }
                    $this->setQueueError("任务执行失败:音频生成失败{$r}");
                }
            }

            $progress=5;
        }
        if($progress == 5){
            $this->checkBeans($task,5,$task_run_log_id);
            //视频生成
            $this->setQueueProgress("开始视频生成,请稍等...", 80);
            RedianTask::mQuery()->where([ "id"=>$task_id])->update(['progress'=>5]);
            if($task_run_log_id){
                $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['progress'=>5]);
            }
            $redian_data = TaskService::instance()->videoGenerate($task,$task_run_log_id);
            if(empty($redian_data)){
                RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"视频生成失败",'error_status'=>5,'status'=>1]);
                if($task_run_log_id){
                    $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"视频生成失败",'error_status'=>5]);
                }
                $this->setQueueError("任务执行失败:视频生成失败");
            }
            if($task['video_platform']=="HeyGen"){
                //创建视频生成状态查询任务
                sysqueue($task['title']."视频生成状态查询任务", "xbase:heygenRetrieve",  10, $data = [
                    'task_id'=>$task_id,'task_run_log_id'=>$task_run_log_id
                ], $rscript = 1, $loops = 0);
            }


        }





        $this->setQueueProgress("任务完成", 100);
        $this->setQueueSuccess("任务完成");


    }

    //AI改写处理方法
    public function textGenerate($task,$task_run_log_id)
    {
        //查询已改写数量
        $c = RedianData::mQuery()->where(['task_id'=>$task['id'],'gaixie_status'=>2,'task_run_log_id'=>$task_run_log_id])->count();
        if($c>=$task['out_num']){
            return false;
        }
        if($c==0){
            $redian_data = TaskService::instance()->textGenerate($task,$task_run_log_id);
            if($redian_data<$task['out_num']){
                return true;
            }else{
                return false;
            }
        }else{
            $out_redian_data = RedianData::mQuery()->where(['task_id'=>$task['id'],"task_run_log_id"=>$task_run_log_id,'filter_status'=>0])
                ->where('similarity','>',0)->order('similarity desc')->limit(0,($task['out_num']-$c))->select()->toArray();
            if(!empty($out_redian_data)){
                $out_redian_data_ids = array_column($out_redian_data,'id');
                RedianData::mQuery()->whereIn('id',$out_redian_data_ids)->update(['filter_status'=>1]);
                $redian_data = TaskService::instance()->textGenerate($task,$task_run_log_id);
                if($redian_data<$task['out_num']){
                    return true;
                }else{
                    return false;
                }
            }else{
                return false;
            }
        }


    }

    //数据采集及匹配度计算方法
    public function dataMatch($task,$task_run_log_id)
    {
        $task_id = $task['id'];
        RedianTask::mQuery()->where([ "id"=>$task_id])->update(['progress'=>1]);
        if($task_run_log_id){
            $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['progress'=>1]);
        }
        //计算最大采集数据量
        $max_data_num = $task['out_num']*10;
        //已采集数据量
        $data_num = 0;
        //执行次数
        $execute_num =1;
        $flag = true;
        while ($data_num<$max_data_num && $flag){
            $this->setQueueProgress("开始采集,第{$execute_num}次执行请稍等...", 0);
            $res = TaskService::instance()->startGatherCoze($task,$execute_num);
            if($res['code']==0){
                RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"采集失败:".$res['msg'],'error_status'=>1,'status'=>1]);
                if($task_run_log_id){
                    $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"采集失败",'error_status'=>1]);
                }
                $this->setQueueError("任务执行失败:采集失败");
                return false;
            }else{
                sleep(10);
                $execute_id = $res['data'];
                $i = 0;
                $WorkflowResult  = 0;
                while ( $i<$max_data_num){
                    //采集状态查询
                    $this->setQueueProgress("查询采集结果,请稍等...".$execute_id, 0);
                    $WorkflowResult = $res = TaskService::instance()->getWorkflowResult($task,$execute_id,$task_run_log_id);
                    $this->setQueueProgress("第{$i}次采集结果,".json_encode($res), 0);
                    if($res==0){
                        RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"查询采集结果失败:".$res['msg'],'error_status'=>1,'status'=>1]);
                        if($task_run_log_id){
                            $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"采集失败:查询采集结果失败"]);
                        }
                        $this->setQueueError("任务执行失败:查询采集结果失败");
                        return false;

                    }elseif ($res==1){
                        //采集成功
                        break;
                    }elseif($res==3){
                        //没有数据了
                        $flag = false;
                        break;
                    }else{
                        sleep(60);
                    }
                    $i++;

                }

                if($WorkflowResult==3 ){
                    $r = RedianData::mQuery()->where(['task_id'=>$task_id,"task_run_log_id"=>$task_run_log_id])->count();
                    if($r==0){
                        RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"采集失败:无采集结果",'error_status'=>1,'status'=>1]);
                        if($task_run_log_id){
                            $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"采集失败:无采集结果",'error_status'=>1]);
                        }
                        $this->setQueueError("任务执行失败:无采集结果");
                        return false;
                    }else{
                        $flag  = false;
                    }

                }
            }
            $r = RedianData::mQuery()->where(['task_id'=>$task_id,"task_run_log_id"=>$task_run_log_id])->whereNull('similarity')->count();
            if($r>0){
                $this->setQueueProgress("计算匹配度,请稍等...", 0);
                RedianTask::mQuery()->where([ "id"=>$task_id])->update(['progress'=>2]);
                $batch_similarity_num = 1;
                $batch_id = 0;
                while ($batch_similarity_num<5){
                    $b_r = TaskService::instance()->batchSimilarity($task,$task_run_log_id);
                    if($b_r){
                        $batch_id = $b_r;
                        break;
                    }
                    $batch_similarity_num++;
                    sleep(30);
                }
                if($batch_id==0&& $execute_num==1){
                    RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"相似度计算失败,任务创建失败",'error_status'=>2,'status'=>1]);
                    if($task_run_log_id){
                        $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"相似度计算失败,任务创建失败",'error_status'=>2]);
                    }
                    $this->setQueueError("任务执行失败:相似度计算失败,任务创建失败");
                    return false;
                }
                //查询相似度计算结果
                $batch_similarity_result_num = 1;
                $similarity_result = 0;
                $this->setQueueProgress("查询计算匹配度,请稍等...", 0);
                while ($batch_similarity_result_num<15 && $batch_id!=0){
                    $this->setQueueProgress("第{$batch_similarity_result_num}次查询计算匹配度,请稍等...", 0);
                    sleep(60);
                    $similarity_result = TaskService::instance()->batchSimilarityResult($task['user_id'],$batch_id);
                    $n= json_encode($similarity_result);
                    $this->setQueueProgress("第{$batch_similarity_result_num}次查询计算匹配度:{$n}", 0);
                    if(($similarity_result==0 || $similarity_result==3)&& $execute_num==1){
                        RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"相似度计算失败",'error_status'=>2,'status'=>1]);
                        if($task_run_log_id){
                            $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"相似度计算失败",'error_status'=>2]);
                        }
                        $this->setQueueError("任务执行失败:相似度计算失败");
                    }

                    if($similarity_result==2){
                        break;
                    }
                    $batch_similarity_result_num++;
                }
                if($similarity_result==1){
                    //如果批量任务一直在等待中,则取消该批量任务,改为单个任务
                    $this->setQueueProgress("批量任务一直在等待中,则取消该批量任务,改为单个任务,请稍等...", 0);
                    TaskService::instance()->cancelBatch($task['user_id'],$batch_id);
                    $redian_data = TaskService::instance()->similarity($task,$task_run_log_id);
                    if(empty($redian_data) && $execute_num==1){
                        RedianTask::mQuery()->where([ "id"=>$task_id])->update(['error_msg'=>"相似度计算失败",'error_status'=>2,'status'=>1]);
                        if($task_run_log_id){
                            $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"相似度计算失败",'error_status'=>2]);
                        }
                        $this->setQueueError("任务执行失败:相似度计算失败");
                        return false;
                    }
                }

            }

            $out_redian_data = RedianData::mQuery()->where(['task_id'=>$task_id,"task_run_log_id"=>$task_run_log_id])
                ->where('similarity','>',79)->order('similarity desc')->select()->toArray();
            $data_num = RedianData::mQuery()->where(['task_id'=>$task_id,"task_run_log_id"=>$task_run_log_id])->count();
            if($task['out_num']<=count($out_redian_data)){
                break;
            }
            $execute_num++;
        }
       // $this->app->log->info("匹配度计算完成Task".json_encode($task));
        $out_redian_data = RedianData::mQuery()->where(['task_id'=>$task_id,"task_run_log_id"=>$task_run_log_id])
            ->where('similarity','>',79)->order('similarity desc')->limit(0,$task['out_num'])->select()->toArray();
       // $this->app->log->info("匹配度计算完成out_redian_data".json_encode($out_redian_data));
         $out_redian_data_ids = array_column($out_redian_data,'id');
       // $this->app->log->info("匹配度计算完成out_redian_data_ids".json_encode($out_redian_data_ids));
         $r = RedianData::mQuery()->whereIn('id',$out_redian_data_ids)->update(['filter_status'=>1]);
         return $r;
    }

    public function checkBeans($task,$progress,$task_run_log_id)
    {
        $beans = MemberService::instance()->getUserRemainingBeans($task['user_id']);
        if($beans<2){
            RedianTask::mQuery()->where([ "id"=>$task['id']])->update(['error_msg'=>"蓝豆不足",'error_status'=>$progress,'status'=>1]);
            if($task_run_log_id){
                $this->app->db->name("task_run_log")->where(["id"=>$task_run_log_id])->update(['result'=>"蓝豆不足"]);
            }
            $this->setQueueError("任务执行失败:蓝豆不足");
        }
    }




}
